#ifndef   _WX_FILENAME_H_
#define   _WX_FILENAME_H_

#include "wx/arrstr.h"
#include "wx/filefn.h"
#include "wx/datetime.h"
#include "wx/intl.h"

#if wxUSE_FILE
class wxFile;
#endif

#if wxUSE_FFILE
class wxFFile;
#endif

enum wxPathFormat {
  wxPATH_NATIVE = 0,
  wxPATH_UNIX
};

enum wxPathNormalize {
  wxPATH_NORM_ENV_VARS = 0x0001,
  wxPATH_NORM_DOTS     = 0x0002,
  wxPATH_NORM_TILDE    = 0x0004,
  wxPATH_NORM_CASE     = 0x0008,
  wxPATH_NORM_ABSOLUTE = 0x0010,
  wxPATH_NORM_LONG =     0x0020,
  wxPATH_NORM_SHORTCUT = 0x0040,
  wxPATH_NORM_ALL      = 0x00ff & ~wxPATH_NORM_CASE
};

enum {
  wxPATH_GET_VOLUME    = 0x0001,
  wxPATH_GET_SEPARATOR = 0x0002
};

enum {
  wxPATH_MKDIR_FULL    = 0x0001
};

extern wxULongLong wxInvalidSize;

class wxFileName {
  public:
    wxFileName() { Clear(); }
    wxFileName( const wxFileName& filepath ) {
      Assign( filepath );
    }
    wxFileName( const wxString& fullpath, wxPathFormat format = wxPATH_NATIVE ) { Assign( fullpath, format ); }
    wxFileName( const wxString& path, const wxString& name, wxPathFormat format = wxPATH_NATIVE ) {
      Assign( path, name, format );
    }
    wxFileName( const wxString& volume, const wxString& path, const wxString& name,
                const wxString& ext, wxPathFormat format = wxPATH_NATIVE ) {
      Assign( volume, path, name, ext, format );
    }
    wxFileName( const wxString& path, const wxString& name,
                const wxString& ext, wxPathFormat format = wxPATH_NATIVE ) {
      Assign( path, name, ext, format );
    }
    void Assign( const wxFileName& filepath );
    void Assign( const wxString& fullpath, wxPathFormat format = wxPATH_NATIVE );
    void Assign( const wxString& volume, const wxString& path, const wxString& name,
                 const wxString& ext, bool hasExt, wxPathFormat format = wxPATH_NATIVE );
    void Assign( const wxString& volume, const wxString& path, const wxString& name,
                 const wxString& ext, wxPathFormat format = wxPATH_NATIVE ) {
      Assign( volume, path, name, ext, !ext.empty(), format );
    }
    void Assign( const wxString& path, const wxString& name, wxPathFormat format = wxPATH_NATIVE );
    void Assign( const wxString& path, const wxString& name, const wxString& ext, wxPathFormat format = wxPATH_NATIVE );
    void AssignDir( const wxString& dir, wxPathFormat format = wxPATH_NATIVE );
    wxFileName& operator=( const wxFileName& filename ) { Assign( filename ); return *this; }
    wxFileName& operator=( const wxString& filename ) { Assign( filename ); return *this; }
    void Clear();
    static wxFileName FileName( const wxString& file, wxPathFormat format = wxPATH_NATIVE );
    static wxFileName DirName( const wxString& dir, wxPathFormat format = wxPATH_NATIVE );
    bool IsOk() const {
      return m_dirs.size() != 0 || !m_name.empty() || !m_relative ||
             !m_ext.empty() || m_hasExt;
    }
    bool FileExists() const;
    static bool FileExists( const wxString &file );
    bool DirExists() const;
    static bool DirExists( const wxString &dir );
    bool IsDirWritable() const { return wxIsWritable( GetPath() ); }
    static bool IsDirWritable( const wxString &path ) { return wxDirExists( path ) && wxIsWritable( path ); }
    bool IsDirReadable() const { return wxIsReadable( GetPath() ); }
    static bool IsDirReadable( const wxString &path ) { return wxDirExists( path ) && wxIsReadable( path ); }
    bool IsFileWritable() const { return wxIsWritable( GetFullPath() ); }
    static bool IsFileWritable( const wxString &path ) { return wxFileExists( path ) && wxIsWritable( path ); }
    bool IsFileReadable() const { return wxIsReadable( GetFullPath() ); }
    static bool IsFileReadable( const wxString &path ) { return wxFileExists( path ) && wxIsReadable( path ); }
    bool IsFileExecutable() const { return wxIsExecutable( GetFullPath() ); }
    static bool IsFileExecutable( const wxString &path ) { return wxFileExists( path ) && wxIsExecutable( path ); }
    bool SetTimes( const wxDateTime *dtAccess, const wxDateTime *dtMod, const wxDateTime *dtCreate );
    bool Touch();
    bool GetTimes( wxDateTime *dtAccess, wxDateTime *dtMod, wxDateTime *dtCreate ) const;
    wxDateTime GetModificationTime() const {
      wxDateTime dtMod;
      ( void )GetTimes( NULL, &dtMod, NULL );
      return dtMod;
    }
    void AssignCwd( const wxString& volume = wxEmptyString );
    static wxString GetCwd( const wxString& volume = wxEmptyString );
    bool SetCwd();
    static bool SetCwd( const wxString &cwd );
    void AssignHomeDir();
    static wxString GetHomeDir();
    static wxString GetTempDir();
    void AssignTempFileName( const wxString& prefix );
    static wxString CreateTempFileName( const wxString& prefix );
    void AssignTempFileName( const wxString& prefix, wxFile *fileTemp );
    static wxString CreateTempFileName( const wxString& prefix, wxFile *fileTemp );
    void AssignTempFileName( const wxString& prefix, wxFFile *fileTemp );
    static wxString CreateTempFileName( const wxString& prefix, wxFFile *fileTemp );
    bool Mkdir( int perm = 0777, int flags = 0 );
    static bool Mkdir( const wxString &dir, int perm = 0777, int flags = 0 );
    bool Rmdir();
    static bool Rmdir( const wxString &dir );
    bool Normalize( int flags = wxPATH_NORM_ALL, const wxString& cwd = wxEmptyString, wxPathFormat format = wxPATH_NATIVE );
    bool MakeRelativeTo( const wxString& pathBase = wxEmptyString, wxPathFormat format = wxPATH_NATIVE );
    bool MakeAbsolute( const wxString& cwd = wxEmptyString, wxPathFormat format = wxPATH_NATIVE ) {
      return Normalize( wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE |
                        wxPATH_NORM_TILDE, cwd, format );
    }
    bool SameAs( const wxFileName& filepath, wxPathFormat format = wxPATH_NATIVE ) const;
    bool operator==( const wxFileName& filename ) const { return SameAs( filename ); }
    bool operator!=( const wxFileName& filename ) const { return !SameAs( filename ); }
    bool operator==( const wxString& filename ) const { return SameAs( wxFileName( filename ) ); }
    bool operator!=( const wxString& filename ) const { return !SameAs( wxFileName( filename ) ); }
    bool IsAbsolute( ) const;
    bool IsRelative( wxPathFormat format = wxPATH_NATIVE ) const { return !IsAbsolute( ); }
    static wxString GetForbiddenChars( wxPathFormat format = wxPATH_NATIVE );
    static bool IsPathSeparator( wxChar ch, wxPathFormat format = wxPATH_NATIVE );
    size_t GetDirCount() const { return m_dirs.size(); }
    void AppendDir( const wxString& dir );
    void PrependDir( const wxString& dir );
    void InsertDir( size_t before, const wxString& dir );
    void RemoveDir( size_t pos );
    void RemoveLastDir() { RemoveDir( GetDirCount() - 1 ); }
    void SetExt( const wxString &ext ) { m_ext = ext; m_hasExt = !m_ext.empty(); }
    void ClearExt() { m_ext = wxEmptyString; m_hasExt = false; }
    void SetEmptyExt() { m_ext = wxT( "" ); m_hasExt = true; }
    wxString GetExt() const { return m_ext; }
    bool HasExt() const { return m_hasExt; }
    void SetName( const wxString &name ) { m_name = name; }
    wxString GetName() const { return m_name; }
    bool HasName() const { return !m_name.empty(); }
    void SetVolume( const wxString &volume ) { m_volume = volume; }
    wxString GetVolume() const { return m_volume; }
    bool HasVolume() const { return !m_volume.empty(); }
    void SetFullName( const wxString& fullname );
    wxString GetFullName() const;
    const wxArrayString& GetDirs() const { return m_dirs; }
    wxString GetPath( int flags = wxPATH_GET_VOLUME, wxPathFormat format = wxPATH_NATIVE ) const;
    void SetPath( const wxString &path, wxPathFormat format = wxPATH_NATIVE );
    wxString GetFullPath( wxPathFormat format = wxPATH_NATIVE ) const;
    wxString GetShortPath() const;
    wxString GetLongPath() const;
    bool IsDir() const { return m_name.empty() && m_ext.empty(); }
    static void SplitPath( const wxString& fullpath, wxString *volume, wxString *path, wxString *name,
                           wxString *ext, bool *hasExt = NULL, wxPathFormat format = wxPATH_NATIVE );
    static void SplitPath( const wxString& fullpath, wxString *volume, wxString *path,
                           wxString *name, wxString *ext, wxPathFormat format ) {
      SplitPath( fullpath, volume, path, name, ext, NULL, format );
    }
    static void SplitPath( const wxString& fullpath, wxString *path, wxString *name,
                           wxString *ext, wxPathFormat format = wxPATH_NATIVE );
    static void SplitVolume( const wxString& fullpathWithVolume, wxString *volume, wxString *path );
    static wxString StripExtension( const wxString& fullpath );
    wxULongLong GetSize() const;
    static wxULongLong GetSize( const wxString &file );
    wxString GetHumanReadableSize( const wxString &nullsize = wxGetTranslation( wxT( "Not available" ) ),
                                   int precision = 1 ) const;
    static wxString GetHumanReadableSize( const wxULongLong &sz,
                                          const wxString &nullsize = wxGetTranslation( wxT( "Not available" ) ),
                                          int precision = 1 );

    #ifndef __DIGITALMARS__
    wxString GetPath( bool withSep, wxPathFormat format = wxPATH_NATIVE ) const {
      return GetPath( withSep ? wxPATH_GET_SEPARATOR : 0, format );
    }
    #endif
    wxString GetPathWithSep( wxPathFormat format = wxPATH_NATIVE ) const {
      return GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR, format );
    }
  private:
    static bool IsValidDirComponent( const wxString& dir );
    wxString        m_volume;
    wxArrayString   m_dirs;
    wxString        m_name, m_ext;
    bool            m_relative;
    bool            m_hasExt;
};

#endif

